home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Collections: Camelot
/
Camelot 134 (1991-10)(Swedish User Group of Amiga)(SE)(PD)[WB].zip
/
Camelot 134 (1991-10)(Swedish User Group of Amiga)(SE)(PD)[WB].adf
/
vocab
/
vocab.c
< prev
Wrap
C/C++ Source or Header
|
1991-08-22
|
11KB
|
532 lines
#define INFO "\
vocab -- A data dumper\n\
Copyleft (c) 1991 by Mike Threepoint. All rights reversed.\n\
Release 6 / Serial number 910608\n\
\n\
Display a vocabulary list of an Infocom(tm) adventure game data file.\n\
\n\
Usage: vocab [-1] [-w] [-#] [-f] file...\n\
\n\
\t-1 one-column list\n\
\t-w wide list (default)\n\
\t-# toggle word numbers\n\
\t-f toggle flags\n\
\n"
/* Now you can:
* make sure you've seen every last Encyclopedia Frobizzica entry,
* learned every spell in the Enchanter series,
* know all the magic wand's F-words,
* discover obscure synonyms (like calling the Zorkian elvish sword
* Glamdring, the dragon Smaug, and the robot R2D2)
* learn trivia about the game's internal operations (like the internal
* `intnum' noun in several games, used when you type a number)
* play with curious debugging commands hidden in some games (Stu Galley's
* works are good for this)
*
* I doubt Infocom's employees will complain, either of them. Alas, Infocom.
* I wore a black armband when you went under. If only you'd stayed solvent.
* (At least till I could buy Sherlock and Arthur! Can't purchase them
* anywhere anymore...)
*
* Email correspondence to linhart@remus.rutgers.edu.
*
* Disclaimer: This program works for me, at the moment. I've never seen
* any Infocom source code(*). Nobody within the company told
* me any technical details. I'm just an independent public
* domain software author. If I-Need-Magic sues, I'll
* cheerfully turn over all zero profits I made on this program.
*
* * (Well, maybe one function. I noticed the Beyond Zork MS-DOS interpreter
* was in MSC, so I mailed them a MSC function to get the screen size from
* the BIOS instead of the stupid SETUP.EXE method, so the interpreter
* could figure out when my VGA was in 50 line mode. Some time later, a
* new text game was released, with VisiClues. I started it in 50-line
* mode, but the screen was reset to 25-line CGA color mode. And then the
* text ran off the bottom of the screen and scrolled as if it were still
* 50 lines long. I'd mail another helpful letter, but it's too late now.)
*/
#define MAXCOL 79
#define BUFSIZ 512
#if !defined(__STDC__) && !defined(__GNUC__) && !defined(__TURBOC__)
#error This is an ANSI-complaint. It looks like you are not ANSI-compliant.
#endif
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
#ifndef SEEK_SET
#define SEEK_SET 0
#endif
#define S_BLANK 1
#define S_MACRO1 2
#define S_MACRO2 3
#define S_MACRO3 4
#define S_CAPS 5
#define S_PUNC 6
#define S_FILLER 6
#define S_OFF 7
/* the 5-bit character set */
const char err_chars[7] = {
/* null thrown in for string handling */
'\0',
/* special codes above */
' ', '1', '2', '3', '^', '@',
/* followed by: */
};
typedef const char alfabet[26];
alfabet
lower = {
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'
},
upper = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'
},
punct = {
'\0' /* ASCII literal */, '\n',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'.', ',', '!', '?', '_', '#', '\'', '\"', '/', '\\', '-', ':', '(', ')'
};
char *macros[3][32];
typedef unsigned char byte;
typedef unsigned short word;
typedef unsigned short z_word;
struct info_header {
byte z_version;
byte flags;
z_word release;
z_word resident_size;
z_word game_offset;
z_word vocab_offset;
z_word object_offset;
z_word variable_offset;
z_word save_area_size;
z_word script_status;
char rev_date[6];
z_word macro_offset;
z_word verify_length;
z_word verify_checksum;
z_word reserved[17];
};
FILE *infile;
short column = 0,
columns = 0;
char show_flags = 0,
numbers = 0,
macro_dump = 0,
did_file = 0;
unsigned
unzword ( z_word z )
{
byte *zp = (byte *)&z;
return (zp[0] << 8) + zp[1];
}
void
newline ( void )
{
putchar('\n');
column = 0;
}
short
end_of_text ( word chars )
{
return chars >> 15;
}
char *
expand ( word chars )
{
static char buf[4] = {0, 0, 0, 0};
buf[2] = (chars & 0x1F) + 1;
chars >>= 5;
buf[1] = (chars & 0x1F) + 1;
chars >>= 5;
buf[0] = (chars & 0x1F) + 1;
return buf;
}
char *
decode ( char *s )
{
int len = strlen(s);
static char new[BUFSIZ];
unsigned newlen = 0;
while (s[len-1] == S_FILLER)
s[--len] = '\0';
while (*s) {
switch (*s) {
case S_MACRO1:
case S_MACRO2:
case S_MACRO3:
#ifdef VOCAB_ALONE
/* shouldn't appear in vocabulary list */
new [ newlen++ ] = err_chars[*s];
#else
{
char *tmp = macros[(*s)-2][(*(s+1))-1];
s++;
if (tmp) {
strcpy(&new [ newlen ], tmp);
newlen += strlen(tmp);
}
}
#endif
break;
case S_CAPS:
if (*(s+1) >= S_OFF)
new [ newlen++ ] = upper[*++s - S_OFF];
else
new [ newlen++ ] = err_chars[S_CAPS];
break;
case S_PUNC:
if (*(s+1) >= S_OFF)
if (*++s == S_OFF) {
new [ newlen ] = ((*++s - 1) & 0x03) << 5;
new [ newlen++ ] += *++s - 1;
} else
new [ newlen++ ] = punct[*s - S_OFF];
else
new [ newlen++ ] = err_chars[S_PUNC];
break;
case S_BLANK:
new [ newlen++ ] = ' ';
break;
default:
new [ newlen++ ] = lower[*s - S_OFF];
}
s++;
}
new [ newlen ] = '\0';
return new;
}
void
disp_ch ( char x )
{
putchar(x);
column++;
}
void
disp_str ( char *fmt, ... )
{
va_list argptr;
static char buf[16];
short len;
va_start(argptr, fmt);
vsprintf(buf, fmt, argptr);
va_end(argptr);
len = strlen(buf);
printf(buf);
column += len;
}
void
disp_bits ( char c )
{
unsigned b;
disp_ch(' ');
for (b = 0x80; b; b >>= 1)
disp_ch(c & b ? '1' : '0');
}
void
error ( char *fmt, ... )
{
va_list argptr;
fprintf(stderr, "\nError: ");
va_start(argptr, fmt);
vfprintf(stderr, fmt, argptr);
va_end(argptr);
exit(1);
}
void
read_error ( void )
{
error("Can't read file at offset %04X.\n", ftell(infile));
}
void
seek_pos ( unsigned long pos )
{
if (fseek(infile, pos, SEEK_SET) != 0)
error("Can't seek offset %04lX.\n", pos);
}
void
dump_vocab ( unsigned long pos )
{
register unsigned count = 0, index;
word words;
int vocab_entry_size;
byte letters_per_word,
zwords_per_word;
short entry_width,
entries_per_line;
char format[sizeof("%%-%ds")];
int punct;
char * buf;
#ifdef DEBUG
printf("Vocabulary table at offset %04X\n", pos);
#endif
seek_pos(pos);
/* list of punctuation characters */
if ((punct = getc(infile)) == EOF)
read_error();
if (punct) {
printf("Punctuation: ");
for (; punct; punct--)
putchar(getc(infile));
putchar('\n');
}
/* size of each vocabulary entry */
if ((vocab_entry_size = getc(infile)) == EOF)
read_error();
/* number of entries */
if (fread(&words, sizeof(words), 1, infile) < 1)
read_error();
words = unzword(words);
if (!numbers)
printf("%u vocabulary entries\n", words);
letters_per_word = (vocab_entry_size - 3) / 2 * 3;
zwords_per_word = letters_per_word / 3;
entry_width = letters_per_word + 2;
if (numbers)
entry_width += 5;
if (show_flags)
entry_width += 3 * (columns == 1 ? 9 : 3) + 1;
entries_per_line = columns ? columns : (MAXCOL + 2) / entry_width;
buf = malloc(letters_per_word + 1);
sprintf(format, "%%-%ds", letters_per_word);
while ( count < words ) {
byte flags[3];
++count;
if (numbers)
disp_str("%04d ", count);
for (index = 0; index < zwords_per_word; index++) {
word z;
if (fread(&z, sizeof(z), 1, infile) < 1)
read_error();
z = unzword(z);
if (index)
strcat(buf, expand(z));
else
strcpy(buf, expand(z));
}
disp_str(format, decode(buf));
if (fread(flags, sizeof(char), 3, infile) < 3)
read_error();
if (show_flags) {
register short n;
disp_ch(' ');
for (n = 1; n <= 3; n++)
if (columns == 1)
disp_bits(flags[n]);
else
disp_str(" %02x", flags[n]);
}
if (entries_per_line > 1 && (count % entries_per_line))
disp_str(" ");
else
newline();
}
free(buf);
if (column)
newline();
}
#ifndef VOCAB_ALONE
void
read_macros ( unsigned long pos )
{
register short table, elem;
z_word macro_offsets[3][32];
seek_pos(pos);
fread(macro_offsets, sizeof(z_word), 3 * 32, infile);
for (table = 0; table < 3; table++)
for (elem = 0; elem < 32; elem++) {
macros[table][elem] = NULL;
if (macro_dump)
printf("Macro %d-%02d: ", table, elem);
if ((pos = unzword(macro_offsets[table][elem])) != 0) {
char macro[BUFSIZ];
z_word z;
char *text;
seek_pos(pos *= sizeof(z_word));
macro[0] = '\0';
do {
if (fread(&z, sizeof(z), 1, infile) < 1)
read_error();
z = unzword(z);
if (macro[0])
strcat(macro, expand(z));
else
strcpy(macro, expand(z));
} while (!end_of_text(z));
text = decode(macro);
macros[table][elem] = malloc(strlen(text) + 1);
strcpy(macros[table][elem], text);
if (macro_dump)
printf("\"%s\"\n", text);
}
}
}
#endif
void
frob_file ( const char *filename )
{
struct info_header header;
if((infile = fopen(filename, "rb")) == NULL)
error("Can't open file \"%s\".\n", filename);
printf("%s:\n", filename);
if (fread(&header, sizeof(header), 1, infile) < 1)
read_error();
printf("Release %u / Serial number %.6s\n", unzword(header.release), &header.rev_date[0]);
if (macro_dump)
read_macros(unzword(header.macro_offset));
dump_vocab(unzword(header.vocab_offset));
fclose(infile);
}
#ifndef LINT
const char sccsid[] = "@(#) " __FILE__ " by Mike Threepoint compiled " __DATE__;
#endif
void
info ( void )
{
puts(INFO);
exit(0);
}
void
parse_opt ( char p )
{
switch (p) {
case 'w':
columns = 0;
break;
case '#':
case 'n':
numbers = !numbers;
break;
case 'f':
case 'b':
show_flags = !show_flags;
break;
#ifndef VOCAB_ALONE
case 'm':
macro_dump = !macro_dump;
break;
#endif
case 'h':
case '?':
info();
break;
default:
if (isdigit(p))
columns = (p - '0');
}
}
void
parse ( char *parm )
{
switch (*parm) {
case '/':
parse_opt(*++parm);
break;
case '-':
while (*++parm) parse_opt(*parm);
break;
default:
if (did_file) newline();
frob_file(parm);
did_file = 1;
}
}
int
main ( const unsigned argc, char *argv[] )
{
if (argc > 1) {
register count;
if (strcmp(argv[1], "?") == 0)
info();
for (count = 1; count < argc; count++)
parse(argv[count]);
if (did_file) return 0;
}
info();
return 1;
}